// 测试el等级切换
// 两次系统调用，一次手动异常返回，一次系统调用异常返回， el3->el0->el3->el0->el3

.global _start

#define OUT_BASE_ADDR 0x13000000

_start:
    // 设置特权指令hvc，smc有效
    // enable: b[8].HCE=1, b[7].SMD=0
    // 主要是hvc， hvc必须启用
    // b[0].ns=1 非安全， b[0].ns=1 安全（默认)
    // mov x0, #0x530
    mov x0, #0x531
    msr scr_el3, x0

    // 设置el1/el0执行模式（aarch32/aarch64）
    // hcr_el2[31]=1:aarch64, hcr_el2[31]=0:aarch32
    mov x0, #0x80000000
    msr hcr_el2, x0

    // 设置异常处理向量入口地址为 x0的值
    msr VBAR_EL1, x0
    msr VBAR_EL2, x0
    msr VBAR_EL3, x0

    bl _exp_vec_init

    b _el3_entry

.align 4
_exit_flag:
    .word 0x0

_exit:
    mov x0, # OUT_BASE_ADDR
    mov w1, #0x4
    strb w1, [x0]
    ldr x3, =_exit_flag
    ldr w0, [x3]
    cmp w0, wzr
    b.eq _ret_exit
    wfi
    b _exit
_ret_exit:
    mov x0, #1
    str w0, [x3]
    ret

_show_current_el:
    mrs x10, currentel
    ret

_hello_world:
    mov x9, #98
    mov x8, #4
    mov x10, # OUT_BASE_ADDR
_loop_hello_world:
    strb w9, [x10]
    sub x8, x8, #1
    cmp x8, #0
    b.ne _loop_hello_world
    ret

// =========== el3 =================
_el3_entry:
    // 设置异常返回地址
    ldr x0, =_el2_entry
    msr elr_el3, x0

    // 设置异常等级， b[3:2]=el, b[1]=res0, b[0]=1:sp_elx, b[0]=0:sp_el0
    mov x0, #0x03c9 // el2_h
    // mov x0, #0x03c8 // el2_t
    // mov x0, #0x03c5 // el1_h
    // mov x0, #0x03c4 // el1_t
    // mov x0, #0x03c0 // el0_t
    msr SPSR_EL3, x0
    eret
    b _el3_entry


// ============== el2 ============
_el2_entry:
    // 设置异常返回地址
    ldr x0, =_el1_entry
    msr elr_el2, x0

    // 设置异常等级， b[3:2]=el, b[1]=res0, b[0]=1:sp_elx, b[0]=0:sp_el0
    // mov x0, #0x03c9 // el2_h
    // mov x0, #0x03c8 // el2_t
    mov x0, #0x03c5 // el1_h
    // mov x0, #0x03c4 // el1_t
    // mov x0, #0x03c0 // el0_t
    msr SPSR_EL2, x0
    eret
    b _el2_entry

// ============= el1 =============
_el1_entry:
    // 设置异常返回地址
    ldr x0, =_el0_entry
    msr elr_el1, x0
    // 设置异常等级， b[3:2]=el, b[1]=res0, b[0]=1:sp_elx, b[0]=0:sp_el0
    // mov x0, #0x03c9 // el2_h
    // mov x0, #0x03c8 // el2_t
    // mov x0, #0x03c5 // el1_h
    // mov x0, #0x03c4 // el1_t
    mov x0, #0x03c0 // el0_t
    msr SPSR_EL1, x0
    eret
    b _el1_entry

// ============= el0 ==============
_el0_entry:
    bl _hello_world
    svc #0
    wfe
    b _el0_entry

// ============ execption handle codes=============
_el3_ecp_handle:
    bl _show_current_el
    bl _exit
    eret

_el2_ecp_handle:
    bl _show_current_el
    smc #0
    eret

_el1_ecp_handle:
    bl _show_current_el
    hvc #0
    eret


// 初始化异常入口程序，动态搬移代码段到异常处理处
_exp_vec_init:
    ldr x1, =_el_entry_vec
    ldr x0, =_el1_ecp_handle
    str x0, [x1]

    ldr x0, =_el2_ecp_handle
    str x0, [x1, #8]!
    
    ldr x0, =_el3_ecp_handle
    str x0, [x1, #8]!

    adr x0, _el_entry_vec_start
    adr x1, _el_entry_vec_end

    // 0x400 表示的是syn event 处理入口向量
    mrs x3, VBAR_EL1
    add x3, x3, 0x400
_loop_move:
    ldr x5, [x0], #0x8 
    str x5, [x3], #0x8 
    cmp x0, x1
    b.lt _loop_move
    ret

_el_entry_vec_start:
// 根据入口设置，通过当前el跳转到相应异常处理程序处
_vec_entry:
    mrs x0, currentel
    lsr x0, x0, #2
    lsl x0, x0, #3
    sub x0, x0, #8
    adr x1, _el_entry_vec
    add x1, x1, x0
    ldr x1, [x1]
    br x1

.align 8
_el_entry_vec:
    .quad 0x0
    .quad 0x0
    .quad 0x0

_el_entry_vec_end:
